/*
 * Copyright (C) 2010 Johan Waldeback
 *  
 * This file is part of the OpenFMS project (http://www.openfms-project.org)
 * 
 * OpenFMS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "ModelSimulator.h"
#include "ModelViewerFrame.h"
#include "SweepDialog.h"
#include <wx/wx.h>

using namespace OpenFms;

/**
 * OpenFms::ModelViewerFrame constructor
 */
ModelViewerFrame::ModelViewerFrame( const wxString &title ) : 
	wxFrame(NULL, wxID_ANY, title ),
	m_pGraphCtrl(NULL)
{
	wxPanel *panel = new wxPanel(this, wxID_ANY);
	Connect( ID_MODELBROWSE, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(ModelViewerFrame::OnBrowseModel) );
	Connect( ID_SIMULATORBROWSE, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(ModelViewerFrame::OnBrowseSimulator) );
	Connect( ID_DOSWEEP, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(ModelViewerFrame::OnDoRead) );

	wxBoxSizer *vbox = new wxBoxSizer(wxVERTICAL);
	wxBoxSizer *hbox1 = new wxBoxSizer(wxHORIZONTAL);
	hbox1->Add( new wxStaticText(panel, wxID_ANY, wxT("Model:")) , 0, wxALIGN_RIGHT, 8 );
	hbox1->Add( new wxTextCtrl( panel, ID_MODELTEXT, wxT("") ), 1 );
	hbox1->Add( new wxButton( panel, ID_MODELBROWSE, wxT("Browse...")), 0 );

	wxBoxSizer *hbox2 = new wxBoxSizer(wxHORIZONTAL);
	hbox2->Add( new wxStaticText(panel, wxID_ANY, wxT("Engine:")) , 0, wxALIGN_RIGHT, 8 );
	hbox2->Add( new wxTextCtrl( panel, ID_SIMULATORTEXT, wxT("") ), 1 );
	hbox2->Add( new wxButton( panel, ID_SIMULATORBROWSE, wxT("Browse...")), 0 );

	const int vmargin = 5;
	vbox->Add(hbox1, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, vmargin);
	vbox->Add(hbox2, 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, vmargin);
	vbox->Add( new wxButton( panel, ID_DOSWEEP, wxT("Do sweep")), 0, wxEXPAND | wxLEFT | wxRIGHT | wxTOP, vmargin );

	m_pGraphCtrl = new GraphCtrl(panel, ID_GRAPH);
	vbox->Add( m_pGraphCtrl, 1, wxEXPAND | wxLEFT | wxRIGHT | wxTOP | wxBOTTOM, vmargin );
	panel->SetSizer(vbox);

}

/**
 * Callback function, called when the user presses the "Browse model..." button.
 */
void ModelViewerFrame::OnBrowseModel( wxCommandEvent &evt )
{
	DoBrowse(ID_MODELTEXT);
}

/**
 * Callback function, called when the user presses the "Browse simulator..." button.
 */
void ModelViewerFrame::OnBrowseSimulator( wxCommandEvent &evt )
{
	DoBrowse(ID_SIMULATORTEXT);
}

/**
 * Opens a file browse dialog
 * @param idTextCtrl Id of a wxTextCtrl receive the name choosen file 
 */
void ModelViewerFrame::DoBrowse( int idTextCtrl )
{
	// create and show dialog
	// do wothing id the users cancels
	wxFileDialog openFileDialog(this);
	if( openFileDialog.ShowModal() == wxID_OK ) {
		// If here, the userhas choosen a file and pressed OK.
		// get (full path) name of the choosed file, and set the value
		// of the specified text control to this.
		wxString filename = openFileDialog.GetPath();
		wxTextCtrl *ctrl = reinterpret_cast<wxTextCtrl *>(this->FindItem(idTextCtrl));
		if( ctrl ) {
			ctrl->SetLabel(filename);
		}
	}
}

/**
 * Callback function, called when the user pressed the "Do Sweep" button
 */
void ModelViewerFrame::OnDoRead( wxCommandEvent &evt )
{
	// get engineFileName and modelFileName from the dialog text controls
	wxTextCtrl *edit = static_cast<wxTextCtrl *>(FindWindowById(ID_MODELTEXT, this));
	assert( edit != NULL ) ;
	if( edit == NULL ) { wxMessageBox(wxT("ERROR: Find ID_MODELTEXT returned NULL")); return; }
	wxString modelFileName = edit->GetValue();
	edit = static_cast<wxTextCtrl *>(FindWindowById(ID_SIMULATORTEXT, this));
	assert( edit != NULL ) ;
	if( edit == NULL ) { wxMessageBox(wxT("ERROR: Find ID_SIMULATORTEXT returned NULL")); return; }
	wxString engineFileName = edit->GetValue();

	// get the graph control
	GraphCtrl *graph = static_cast<GraphCtrl *>(FindWindowById(ID_GRAPH, this));
	assert( graph != NULL ) ;
	if( graph == NULL ) { wxMessageBox(wxT("ERROR: Find ID_GRAPH returned NULL")); return; }

	// create ModelSimulator
	ModelSimulator ms;
	if( ms.load( engineFileName, modelFileName ) == false)
	{
		wxMessageBox(ms.getLastErrorMessage(), wxT("ERROR: Unable to load engine and model"));
		return;
	}

	// Create a sweep dialog
	// In this dialog, the user can specify which parameters to use.
	SweepDialog dlg(this);
	if( dlg.ShowModal() == wxID_OK ) 
	{
		//
		// If here, the iser pressed OK in the sweep dialog - do a sweep
		//

		// create temporary x/y arrays
		float *px = new float[ dlg.getNumberOfSteps() ];
		float *py = new float[ dlg.getNumberOfSteps() ];
		if( px == NULL || py == NULL )
		{
			wxMessageBox(wxT("ERROR: Unable to reserve memory"));
			return;
		}
		
		ModelSimulator_environment_t environment = { sizeof (ModelSimulator_environment_t)}; 
		ModelSimulator_inertias_t inertias = { sizeof (ModelSimulator_inertias_t)};
		ModelSimulator_forces_t forces = { sizeof (ModelSimulator_forces_t)};

		// sweep: fill in the x/y arrays
		for( int i=0; i<dlg.getNumberOfSteps(); ++i) {
			
			// get forces
			if( dlg.get( environment, inertias, i ) == false ) {
				wxMessageBox(wxT("ERROR: dlg.get( environment, inertias, i ) failed"));
				return;
			}

			// do simulation
			// todo: add inertias where?
			if( ms.step( environment, forces ) == false ) {
				wxMessageBox(wxT("ERROR: ms.step( environment, forces ) failed"));
				return;
			}

			// extraxt x/y
			px[i] = dlg.select(i);
			py[i] = dlg.select(forces);
		}

		// copy the data to the graph control and redraw it
		graph->setData( px, py, dlg.getNumberOfSteps());
		graph->Refresh();

		// free temporary allocated memory
		delete px;
		delete py;
	}
}


